﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "LineEditDefinition.h"
#include "GbmpNew.h"
#include "LineEditEvent.h"
#include "ControlDefinitionChangeEvent.h"
#include "ILineEditHandler.h"
#include "StringUtil.h"
#include "ValidatorBase.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

gcmp::LineEditDefinition::LineEditDefinition(const std::wstring& id, const std::wstring& caption, LineEditInputType inputType)
    : m_pCtrlItem(NEW_AS_OWNER_PTR(ControlDefinition, id, caption, caption))
    , m_inputType(inputType)
    , m_selectionStart(-1)
    , m_selectedText(L"")
    , m_decimals(3)
    , m_isEditing(false)
{
    m_pEvent = NEW_AS_OWNER_PTR(LineEditEvent, L"LineEditEvent", this);
    m_pDefinitionChangeEvent = NEW_AS_OWNER_PTR(ControlDefinitionChangeEvent, L"LineEditDefineChangeEvent", this);

}

gcmp::LineEditDefinition::LineEditDefinition(const std::wstring& id, const std::wstring& caption, double value, int decimals /*= 3*/)
    : m_pCtrlItem(NEW_AS_OWNER_PTR(ControlDefinition, id, caption, caption))
    , m_inputType(LineEditInputType::InputDouble)
    , m_selectionStart(-1)
    , m_selectedText(L"")
    , m_decimals(decimals)
    , m_text(StringUtil::ToWString(value,decimals))
    , m_isEditing(false)
{
    m_pEvent = NEW_AS_OWNER_PTR(LineEditEvent, L"LineEditEvent", this);
    m_pDefinitionChangeEvent = NEW_AS_OWNER_PTR(ControlDefinitionChangeEvent, L"LineEditDefineChangeEvent", this);
}

gcmp::LineEditDefinition::~LineEditDefinition()
{

}

bool gcmp::LineEditDefinition::SetText(const std::wstring& text)
{
    m_selectionStart = -1;
    if (m_text != text)
    {
        if (!text.empty() && m_opValidator && !m_opValidator->ValidateInput(text))
        {
            ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
            arguments.SetModifyControlDefinitionId(GetId());
            m_pDefinitionChangeEvent->Emit(&arguments);
            return false;
        }
        else
        {
            m_text = text;
            ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
            arguments.SetModifyControlDefinitionId(GetId());
            m_pDefinitionChangeEvent->Emit(&arguments);

            LineEditEventArgs args(LineEditEventType::TextChanged, GetId(), m_text);
            args.SetTextChangeByUserFlag(LineEditTextChangeFlag::IsTextChangeByUser());
            LineEditEvent* ctrlEvent = dynamic_cast<LineEditEvent*>(m_pEvent.get());
            if (ctrlEvent)
            {
                ctrlEvent->Emit(&args);
            }
            if (m_handler)
            {
                m_handler.Process(&args);
            }
        }
    }
    return true;
}

bool LineEditDefinition::SetIsEditing(bool isEditing)
{
    if (m_isEditing != isEditing)
    {
        m_isEditing = isEditing;

        ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
        arguments.SetModifyControlDefinitionId(GetId());
        m_pDefinitionChangeEvent->Emit(&arguments); 
    }
    if (!isEditing)
    {
        LineEditEvent* ctrlEvent = dynamic_cast<LineEditEvent*>(GetEvent());
        if (ctrlEvent)
        {
            LineEditEventArgs args(LineEditEventType::EditingFinished, GetId(), GetText());
            ctrlEvent->Emit(&args);
        }
    }
    return true;
}

void gcmp::LineEditDefinition::SelectAll()
{
    if (!m_text.empty() && (m_selectedText != m_text || m_selectionStart != 0))
    {
        m_selectedText = m_text;
        m_selectionStart = 0;
        ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
        arguments.SetModifyControlDefinitionId(GetId());
        m_pDefinitionChangeEvent->Emit(&arguments);
    }
}

void gcmp::LineEditDefinition::Clear()
{
    if (!m_text.empty())
    {
        m_text.clear();
        ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
        arguments.SetModifyControlDefinitionId(GetId());
        m_pDefinitionChangeEvent->Emit(&arguments);
    }
}

std::wstring gcmp::LineEditDefinition::GetSelectedText() const
{
    return m_selectedText;
}

bool gcmp::LineEditDefinition::SetValidator(OwnerPtr<ValidatorBase> opValidator)
{
    m_opValidator = TransferOwnership(opValidator);
    return true;
}

ValidatorBase* gcmp::LineEditDefinition::GetValidator()
{
    return m_opValidator.get();
}

gcmp::IControlDefinitionChangeEvent* gcmp::LineEditDefinition::GetControlDefinitionChangeEvent() const
{
    return const_cast<ControlDefinitionChangeEvent*>(m_pDefinitionChangeEvent.get());
}

int gcmp::LineEditDefinition::GetSelectionStart() const
{
    return m_selectionStart;
}

void gcmp::LineEditDefinition::SetSelection(int start, int length)
{
    if (start == -1)
    {
        m_selectedText = L"";
        m_selectionStart = -1;
        ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
        arguments.SetModifyControlDefinitionId(GetId());
        m_pDefinitionChangeEvent->Emit(&arguments);

        return;
    }
    std::wstring text = m_text.substr(start, length);
    if (!m_text.empty() && (m_selectedText != text || m_selectionStart != start))
    {
        m_selectedText = text;
        m_selectionStart = start;
        ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
        arguments.SetModifyControlDefinitionId(GetId());
        m_pDefinitionChangeEvent->Emit(&arguments);
    }
}

bool gcmp::LineEditDefinition::IsVisible() const
{
    if (m_handler)
    {
        return m_handler->IsVisible();
    }
    return m_pCtrlItem->IsVisible();
}

bool gcmp::LineEditDefinition::IsEnabled() const
{
    if (m_handler)
    {
        return m_handler->IsEnabled();
    }
    return m_pCtrlItem->IsEnabled();
}

bool gcmp::LineEditDefinition::SetEnabled(bool enabled)
{
    bool res = m_pCtrlItem->SetEnabled(enabled);
    if (res)
    {
        ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
        m_pDefinitionChangeEvent->Emit(&arguments);
    }
    return res;
}

bool gcmp::LineEditDefinition::SetVisible(bool visible)
{
    bool res = m_pCtrlItem->SetVisible(visible);
    if (res)
    {
        ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
        m_pDefinitionChangeEvent->Emit(&arguments);
    }
    return res;
}

bool gcmp::LineEditDefinition::SetControlHandler(OwnerPtr<ILineEditHandler> pControlHandler)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pControlHandler, L"pControlState为空",L"GDMPLab",L"2024-03-30");
    bool visible = IsVisible();
    bool enabled = IsEnabled();
    ILineEditHandler* pHandler = pControlHandler.get();
    m_handler.SetControlHandler(TransferOwnership(pControlHandler));

    if (visible != pHandler->IsVisible() || enabled != pHandler->IsEnabled())
    {
        ControlDefinitionChangeEventArgs arguments(ControlDefinitionChangeEventType::Other);
        m_pDefinitionChangeEvent->Emit(&arguments);
    }
    return true;
}

bool gcmp::LineEditDefinition::BlockControlHandler(bool needBlock)
{
    return m_handler.BlockControlHandler(needBlock);
}

bool gcmp::LineEditDefinition::IsDoubleValue(const std::wstring& str)
{
    if (str.empty())
    {
        return true;
    }
 
    std::string string = StringUtil::ToString(str);
    if (str[0] == '+' || str[0] == '-')
    {
        std::string temp(str.begin() + 1, str.end());
        string = temp;
    }
    if (string.empty())
    {
        return true;
    }

    double d;
    std::istringstream is(string);
    is >> d;
    return !is.fail() && is.eof();
}

bool gcmp::LineEditDefinition::IsIntValue(const std::wstring& str)
{
    if (str.empty())
    {
        return true;
    }
    std::string string = StringUtil::ToString(str);
    if (str[0] == '+' || str[0] == '-')
    {
        std::string temp(str.begin() + 1, str.end());
        string = temp;
    }
    if (string.empty())
    {
        return true;
    }
    std::stringstream sin(string);
    int d;
    std::istringstream is(string);
    is >> d;
    return !is.fail() && is.eof();
}
